#include "mysql.h"

//连接数据库
int mysqlConnect(MYSQL** sock){
    //为Mysql连接分配资源
    *sock = mysql_init(NULL);
    //连接Mysql到服务端
    MYSQL* ret = mysql_real_connect(*sock,"localhost","root","123","NetDiskThree",0,NULL,0);
    if(ret == NULL){
        fprintf(stderr,"%s:%s\n","mysql_real_connect:",mysql_error(*sock));
        exit(-1);
    }
    return 0;
}
//获取盐值   
int get_salt(char *salt){ //得到的盐值用参数salt 返回给调用函数
    char buf[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";  //盐值取值范围
                                                                                    //printf("sizeof(buf)=%d",sizeof(buf)-1);
    char randvalue[17]={0};
    srand(time(NULL));
    for(int i=0;i<16;i++){
        int index=rand()%(sizeof(buf)-1);//获取随机数
        randvalue[i]=buf[index];
    }
    sprintf(salt,"$6$%s$",randvalue); //盐值开头固定,后续随机盐值 拼接
    return 0;
}

//注册
int register_user(MYSQL *mysql,char *user_name,char *password){
    char buf[1024]={0};
    char salt[25]={0};
    get_salt(salt);//先获取盐值

    char *cipher = crypt(password, salt); //通过密码 和 盐值得到密文(返回值)
    if(cipher == NULL) {
        fprintf(stderr, "crypt error\n");
        return -1;
    }
    //拼接出sql语句
    sprintf(buf,"Insert into user (account,salt,secretPassword,is_deleted) values ('%s','%s','%s','%d');",user_name,salt,cipher,0);
    int qret=mysql_query(mysql,buf);
    if(qret!=0){//不为0说明执行失败
        fprintf(stderr,"%s:%s\n","mysql_query_register",mysql_error(mysql));
        return -1;
    }

    return 0;
}
//登录
int log_on(MYSQL *mysql, char *user_name, char *plain_password, char *ret) { //kang 的明文密码是123456
    char query[1024] = {0};
    //  同时查询 salt 和 加密后的 secretPassword
    sprintf(query, "SELECT salt, secretPassword FROM user WHERE account='%s' AND is_deleted=0", user_name);

    if (mysql_query(mysql, query) != 0) {
        fprintf(stderr, "mysql_query error: %s\n", mysql_error(mysql));
        return -1;
    }

    MYSQL_RES *res = mysql_store_result(mysql);
    if (!res || mysql_num_rows(res) == 0) {
        strcpy(ret, "log_on failed: user not found\n");
        if (res) mysql_free_result(res);
        return -2;
    }

    MYSQL_ROW row = mysql_fetch_row(res);
    const char *salt = row[0];           // 第一列是 salt
    const char *db_crypted = row[1];     // 第二列是数据库中的密文

    char *crypted_input = crypt(plain_password, salt); // 用salt加密明文

    if (strcmp(crypted_input, db_crypted) == 0) {
        strcpy(ret, "log_on success\n");
        strcat(ret, user_name);
        strcat(ret, "-NetDisk:~$/ ");
    } else {
        strcpy(ret, "log_on failed: password mismatch\n");
        mysql_free_result(res);
        return -3;
    }

    mysql_free_result(res);
    return 0;
}

// 将读取到的id路径(1/2/3) 转换为真实路径
int get_full_path(MYSQL *mysql, const char *idPath, char *stackPath) {
    char idPathCopy[1024] = {0};
    strcpy(idPathCopy, idPath);

    char *token = strtok(idPathCopy, "/");
    //切割之后在数据库中依次寻找对应的 真实文件名
    while (token != NULL) {
        char query[256] = {0};
        sprintf(query, "SELECT filename FROM catalog WHERE id = %d",atoi(token));
        printf("切割token: %s ",token);
        int qret = mysql_query(mysql, query);
        if (qret != 0) {
            fprintf(stderr, "mysql_query failed: %s\n", mysql_error(mysql));
            return -1;
        }

        MYSQL_RES *res = mysql_store_result(mysql);
        if (!res) {
            fprintf(stderr, "mysql_store_result failed\n");
            return -1;
        }

        MYSQL_ROW row = mysql_fetch_row(res);
        if (row && row[0]) {
            strcat(stackPath, "/");
            strcat(stackPath, row[0]); // 把文件名拼接进路径
        }

        mysql_free_result(res);

        token = strtok(NULL, "/");
    }

    return 0;
}
// ls命令：查找当前目录下所有子文件、子目录，并存到 result 返回
int ls_order(MYSQL* mysql,const char* user, Link_list_t* list, char* result) {
    bzero(result,4096);
    // 如果栈为空 此时位于家目录,则parent_id为-1;如果否,则栈顶为parent_id
    int parent_id = (list == NULL || list->head == NULL) ? -1 : list->tail->id;

    char sql[1024] = {0};
    //根据用ZZ户名和parent_id查询文件名和其类型
    sprintf(sql, "SELECT filename, type FROM catalog WHERE user='%s' AND parent_id=%d", user, parent_id);

    int qret = mysql_query(mysql, sql);
    if (qret != 0) {
        fprintf(stderr, "mysql_query_ls: %s\n", mysql_error(mysql));
        return -1;
    }

    MYSQL_RES* res = mysql_store_result(mysql);
    if (res == NULL) {
        fprintf(stderr, "mysql_store_result_ls: %s\n", mysql_error(mysql));
        return -1;
    }

    MYSQL_ROW row;
    while ((row = mysql_fetch_row(res))) {
        char line[256] = {0};

        if (strcmp(row[1], "d") == 0) {
            snprintf(line, sizeof(line), "%s/", row[0]);  // 文件夹
        } else {
            snprintf(line, sizeof(line), "%s", row[0]);    // 普通文件
        }

        // 拼接到 result 中
        strcat(result, line);
        strcat(result," ");
    }

    mysql_free_result(res);
    return 0;
}
//进入指定目录
int cd_order(MYSQL *mysql, const char *user, const char *target, Link_list_t *catalog) {
    if (target == NULL || strlen(target) == 0 || strcmp(target, "~") == 0) {
        // 回到根目录
        while (catalog->length > 0) {
            delete_catalog(catalog);
        }
        return 0;
    }

    //    // 是否绝对路径（从根开始）
    //    bool isAbsolutePath = target[0] == '/';
    //    if (isAbsolutePath) {
    //        while (catalog->length > 0) {
    //            delete_catalog(catalog);
    //        }
    //    }

    // 拷贝路径，准备分割
    char pathCopy[1024] = {0};
    strncpy(pathCopy, target, sizeof(pathCopy) - 1);

    char *token = strtok(pathCopy, "/");
    while (token != NULL) {
        if(strcmp(token, "~") == 0){
            while (catalog->length > 0) {
                delete_catalog(catalog);
            }

        }else if (strcmp(token, ".") == 0) {
            // 当前目录，无操作
        } else if (strcmp(token, "..") == 0) {
            // 返回上级目录
            if (catalog->length > 0) {
                delete_catalog(catalog);
            }
        } else if (strlen(token) == 0) {
            // 忽略连续的 "/"
        } else {
            // 进入子目录
            int parent_id = -1;
            if (catalog->length > 0) {
                parent_id = catalog->tail->id;
            }

            int child_id = get_id_by_filename(mysql, user, parent_id, token);
            if (child_id == -1) {
                printf("目录 '%s' 不存在，无法进入\n", token);
                return -1;
            }

            add_catalog(catalog, child_id);
        }
        token = strtok(NULL, "/");
    }

    return 0;
}

// 查询 catalog 表中是否存在符合条件的子目录，返回其 id
int get_id_by_filename(MYSQL *mysql, const char *user, int parent_id, const char *filename) {
    char query[1024] = {0};
    sprintf(query, "SELECT id FROM catalog WHERE filename='%s' AND user='%s' AND parent_id=%d AND type='d'", 
            filename, user, parent_id);

    int qret = mysql_query(mysql, query);
    if (qret != 0) {
        fprintf(stderr, "mysql_query failed: %s\n", mysql_error(mysql));
        return -1;
    }

    MYSQL_RES *res = mysql_store_result(mysql);
    if (res == NULL) {
        fprintf(stderr, "mysql_store_result failed: %s\n", mysql_error(mysql));
        return -1;
    }

    MYSQL_ROW row = mysql_fetch_row(res);
    if (row == NULL) {
        mysql_free_result(res);
        return -1;  // 没找到
    }

    int id = atoi(row[0]);
    mysql_free_result(res);
    return id;
}

//pwd命令
int pwd_order(Link_list_t* list, MYSQL *mysql, char* stackPath){
    bzero(stackPath,1024);
    if (list->head == NULL) {
        strcpy(stackPath, "/"); // 根路径
        return 0;
    }

    char idPath[1024] = {0};
    printf_Linklist(list, idPath);  // 先构造出 ID 路径，比如 3/7/9
    get_full_path(mysql, idPath, stackPath); // 再把这些 ID 转为实际路径
    return 0;
}

// 检查目录下是否存在同名文件或文件夹，返回 1 表示存在，0 表示不存在，-1 表示出错
int check_name_exists(MYSQL *mysql, const char *user, int parent_id, const char *filename) {
    char query[1024] = {0};
    // 注意，这里 type 不限制，文件或目录都不能重名
    sprintf(query, "SELECT id FROM catalog WHERE filename='%s' AND user='%s' AND parent_id=%d", filename, user, parent_id);

    int qret = mysql_query(mysql, query);
    if (qret != 0) {
        fprintf(stderr, "mysql_query failed: %s\n", mysql_error(mysql));
        return -1;
    }

    MYSQL_RES *res = mysql_store_result(mysql);
    if (res == NULL) {
        fprintf(stderr, "mysql_store_result failed: %s\n", mysql_error(mysql));
        return -1;
    }

    int exists = (mysql_num_rows(res) > 0) ? 1 : 0;//如果可以查询到一行数据,就返回1
    mysql_free_result(res);
    return exists;
}

int mkdir_order(MYSQL* mysql, char* folder_name,const char* user, Link_list_t* list) {
    int parentid = -1;  // 根目录
    if (list->head != NULL) {
        parentid = list->tail->id;
    }

    // 先检查是否存在同名文件夹或文件
    int exist = check_name_exists(mysql, user, parentid, folder_name);
    if (exist == 1) {
        printf("目录或文件已存在，不能创建同名文件夹: %s\n", folder_name);
        return -1;  // 不允许创建
    } else if (exist == -1) {
        printf("查询异常，无法判断是否重名\n");
        return -1;
    }

    char sql[4096] = {0};
    char path[1024] = {0};
    if (parentid == -1) {
        //在家目录,则路径path为/
        strcpy(path, "/");
    } else {
        //不在家目录 就查询所处位置,并更新path
        pwd_order(list, mysql, path);
    }
    //插入一行数据到文件表
    sprintf(sql, "INSERT INTO catalog (filename, user, parent_id, md5, type, path) VALUES ('%s', '%s', %d, NULL, 'd', '%s')",
            folder_name, user, parentid, path);

    int qret = mysql_query(mysql, sql);
    if (qret != 0) {
        fprintf(stderr, "mysql_query_mkdir failed: %s\n", mysql_error(mysql));
        return -1;
    }

    return 0;
}
// 判断目录是否为空
int is_dir_empty(MYSQL *mysql, const char *user, int dir_id) {
    char sql[512] = {0};
    //将dir_id作为parent_id去查表,查到的数据则是dir_id目录下的子文件
    sprintf(sql, "SELECT COUNT(*) FROM catalog WHERE user='%s' AND parent_id=%d", user, dir_id);

    if (mysql_query(mysql, sql) != 0) {
        fprintf(stderr, "mysql_query error: %s\n", mysql_error(mysql));
        return -1;
    }

    MYSQL_RES *res = mysql_store_result(mysql);
    if (!res) {
        fprintf(stderr, "mysql_store_result error: %s\n", mysql_error(mysql));
        return -1;
    }

    MYSQL_ROW row = mysql_fetch_row(res);
    int count = atoi(row[0]);
    mysql_free_result(res);

    return count == 0 ? 1 : 0; //返回值为1 则该目录为空,返回值为0 非空
}

// rmdir命令实现
int rmdir_order(MYSQL *mysql, const char *user, const char *dirname, Link_list_t *catalog) {
    if (dirname == NULL || strlen(dirname) == 0) {
        printf("目录名不能为空\n");
        return -1;
    }

    // 1. 获取当前所处目录(栈顶)的id
    int parent_id = (catalog->length == 0) ? -1 : catalog->tail->id;

    // 2. 查找目标 (要删除的目录id)
    int dir_id = get_id_by_filename(mysql, user, parent_id, dirname);
    if (dir_id == -1) {
        printf("要删除的目录不存在\n");
        return -1;
    }

    // 3. 判断目录是否为空
    int empty = is_dir_empty(mysql, user, dir_id);
    if (empty == -1) {
        printf("判断目录是否为空失败\n");
        return -1;
    }
    if (empty == 0) {
        printf("目录非空，不能删除\n");
        return -1;
    }

    // 4. 删除目录记录
    char sql[512] = {0};
    sprintf(sql, "DELETE FROM catalog WHERE id=%d AND user='%s'", dir_id, user);
    if (mysql_query(mysql, sql) != 0) {
        fprintf(stderr, "删除目录失败: %s\n", mysql_error(mysql));
        return -1;
    }

    // 5. 如果目录栈当前目录是被删目录，出栈
    if (catalog->length > 0 && catalog->tail->id == dir_id) {
        delete_catalog(catalog);
    }

    printf("目录删除成功\n");
    return 0;
}

